package it.uniroma2.art.coda.projectionrule.antlr;

import it.uniroma2.art.coda.core.UIMACODAUtilities;
import it.uniroma2.art.coda.exception.PRParserException;
import it.uniroma2.art.coda.projectionrule.GraphStruct;
import it.uniroma2.art.coda.projectionrule.IfElseStruct;
import it.uniroma2.art.coda.projectionrule.PlaceholderStruct;
import it.uniroma2.art.coda.projectionrule.ParserPR;
import it.uniroma2.art.coda.projectionrule.ProjectionRule;
import it.uniroma2.art.coda.projectionrule.ProjectionRulesModel;
import it.uniroma2.art.coda.projectionrule.graph.GraphSingleElemPlaceholder;
import it.uniroma2.art.coda.projectionrule.graph.GraphSingleElemString;
import it.uniroma2.art.coda.projectionrule.graph.GraphSingleElemUri;
import it.uniroma2.art.coda.projectionrule.graph.GraphSingleElemVar;
import it.uniroma2.art.coda.projectionrule.graph.GraphSingleElement;
import it.uniroma2.art.coda.structures.depends.DependencyObjThreeParam;
import it.uniroma2.art.coda.structures.depends.DependencyObjVarParam;
import it.uniroma2.art.coda.structures.depends.DependencyObject;
import it.uniroma2.art.coda.structures.depends.DependencyObjOneParam;
import it.uniroma2.art.coda.structures.depends.DependencyObjTwoParam; //import it.uniroma2.art.coda.utility.FeatAndProperty;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.management.StringValueExp;

import org.antlr.runtime.ANTLRFileStream;
import org.antlr.runtime.CharStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.TokenStream;
import org.antlr.runtime.tree.Tree;
import org.apache.uima.jcas.tcas.Annotation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ANTLRParserPR extends ParserPR {

	// private boolean verbose = true;

	HashMap<String, String> prefixNameSpaceMap;

	private String conf = "CONF";
	private String id = "id";
	private String dependsOn = "dependsOn";
	private String imports = "imports";
	private String alias = "alias";
	private String noalias = "NOALIAS";
	private String nodes = "nodes";
	private String nonodes = "NONODES";
	private String UIMATYPEANDFEATS = "UIMATYPEANDFEATS";
	private String IF = "if";
	private String ELSEIF = "ELSEIF";
	private String ELSE = "ELSE";
	private String graph = "graph";
	private String nograph = "NOGRAPH";
	private String noOptTriple = "triple";
	private String optTriple = "OPTIONALTRIPLE";
	private String where = "where";
	private String nowhere = "NOWHERE";
	private String parameters = "PARAMETERSLIST";
	private String placeholderSwitch = "PLACEHOLDER";
	private String varSwitch = "VAR";
	private String datatypeSwitch = "DATATYPEVALUE";
	private String uimaType = "UIMATYPE";

	// multiple parameters
	private String lastOneOfDep = "lastOneOf";

	private static Logger logger = LoggerFactory.getLogger(ANTLRParserPR.class);

	// private String prClass = "PRClass";
	// private String prProperty = "PRProperty";
	// private String uimaFeat = "UIMAFEAT";
	// private String domains = "DOMAINLIST";
	// private String domain = "domain";
	// private String ranges = "RANGELIST";
	// private String range = "range";
	// private String features = "OTHERFEATURESLIST";
	// private String attribute = "ATTRIBUTE";

	public ANTLRParserPR(String id, String description) {
		super(id, description);
	}

	@Override
	public ProjectionRulesModel parsePR() throws PRParserException {
		CharStream charStream;
		try {
			if (prFilePath == null) {
				throw new PRParserException("antlrFilePath is null");
			}
			charStream = new ANTLRFileStream(prFilePath);
			AntlrLexer lexer = new AntlrLexer(charStream);
			TokenStream token = new CommonTokenStream(lexer);
			AntlrParser parser = new AntlrParser(token);
			Tree tree = (Tree) parser.prRules().getTree();

			logger.debug("tree = " + tree.toStringTree());

			// Prefix part
			Tree prefixTree = tree.getChild(0);
			prefixNameSpaceMap = new HashMap<String, String>();
			for (int i = 0; i < prefixTree.getChildCount(); ++i) {
				Tree singlePrefixTree = prefixTree.getChild(i);
				String prefix = singlePrefixTree.getChild(0).getText();
				if (prefix.startsWith("_"))
					throw new PRParserException("prefix cannot start with _ : " + prefix);
				Tree namespaceTree = singlePrefixTree.getChild(1);
				String namespace = "";
				for (int j = 0; j < namespaceTree.getChildCount(); ++j) {
					namespace += namespaceTree.getChild(j).getText();
				}
				// if(namespace.contains("#") == false)
				// namespace += "#";
				if (prefixNameSpaceMap.containsKey(prefix)) {
					throw new PRParserException("duplicate prefix: " + prefix);
				}
				prefixNameSpaceMap.put(prefix, namespace);
			}

			// now parse the projection rule part
			Tree prRulesTree = tree.getChild(1);
			for (int i = 0; i < prRulesTree.getChildCount(); ++i) {
				Tree prRuleTree = prRulesTree.getChild(i);
				ProjectionRule projRule = parsePRTree(prRuleTree, prefixNameSpaceMap);
				prModel.addProjectionRule(projRule);
			}

			// at the end resolve all the dependency among all the projection rules
			prModel.revolveDependecyAmongProjRules();

		} catch (IOException e) {
			e.printStackTrace();
		} catch (PRParserException e) {
			e.printStackTrace();
		} catch (RecognitionException e) {
			e.printStackTrace();
		} catch (AntlrParserRuntimeException e) {
			throw new PRParserException(e.getMsg());
		}

		return prModel;
	}

	private ProjectionRule parsePRTree(Tree prTree, HashMap<String, String> prefixNameSpaceMap)
			throws PRParserException {

		Collection<String> dynRefIdList = new ArrayList();

		logger.debug("prTree = " + prTree.toStringTree());
		ProjectionRule prRule = null;
		int nextPos = 0;

		// parse the confidence value, if present
		double confDouble;
		if (prTree.getChild(nextPos).getText().compareTo(conf) == 0) {
			confDouble = Double.parseDouble(prTree.getChild(nextPos).getChild(0).getText());
			++nextPos;
		} else
			// if no value is present set it to 1.0
			confDouble = 1.0;

		// UIMATYPE (always present)
		String uimaType = "";
		Tree uimaTypeTree = prTree.getChild(nextPos);
		++nextPos;
		for (int i = 0; i < uimaTypeTree.getChildCount(); ++i) {
			uimaType += uimaTypeTree.getChild(i).getText();
		}

		// ID (if present)
		if (prTree.getChild(nextPos).getText().compareTo(id) == 0) {
			String id = prTree.getChild(nextPos).getChild(0).getText();
			nextPos++;
			prRule = new ProjectionRule(uimaType, confDouble, id);
		} else
			// the id is not present
			prRule = new ProjectionRule(uimaType, confDouble);

		// depends_on (if present) (each particular dependency may have a different number of arguments)
		if (nextPos < prTree.getChildCount() && prTree.getChild(nextPos).getText().compareTo(dependsOn) == 0) {
			Tree dependsOnTree = prTree.getChild(nextPos);
			parseDependsOnTree(prRule, dependsOnTree, true, dynRefIdList);
			nextPos++;
		}

		// imports (if present) (each particular dependency may have a different number of arguments)
		if (nextPos < prTree.getChildCount() && prTree.getChild(nextPos).getText().compareTo(imports) == 0) {
			Tree dependsOnTree = prTree.getChild(nextPos);
			parseDependsOnTree(prRule, dependsOnTree, false, dynRefIdList);
			nextPos++;
		}

		// alias (if present)
		if (nextPos < prTree.getChildCount() && prTree.getChild(nextPos).getText().compareTo(alias) == 0) {
			Tree aliasesTree = prTree.getChild(nextPos);
			parseAliasTree(prRule, aliasesTree);
			nextPos++;
		} else if (nextPos < prTree.getChildCount()
				&& prTree.getChild(nextPos).getText().compareTo(noalias) == 0) {
			nextPos++;
		}

		// nodes (if present) (be careful about the )
		if (nextPos < prTree.getChildCount() && prTree.getChild(nextPos).getText().compareTo(nodes) == 0) {
			Tree nodesTree = prTree.getChild(nextPos);
			parseNodesTree(prRule, nodesTree);
			nextPos++;
		} else if (nextPos < prTree.getChildCount()
				&& prTree.getChild(nextPos).getText().compareTo(nonodes) == 0) {
			nextPos++;
		}

		// graph (if present)
		if (nextPos < prTree.getChildCount() && prTree.getChild(nextPos).getText().compareTo(graph) == 0) {
			Tree graphTree = prTree.getChild(nextPos);
			parseGraphTree(prRule, graphTree, dynRefIdList);
			nextPos++;
		} else if (nextPos < prTree.getChildCount()
				&& prTree.getChild(nextPos).getText().compareTo(nograph) == 0) {
			nextPos++;
		}

		// where (if present)
		if (nextPos < prTree.getChildCount() && prTree.getChild(nextPos).getText().compareTo(where) == 0) {
			Tree whereTree = prTree.getChild(nextPos);
			parseWhereTree(prRule, whereTree, dynRefIdList);
			nextPos++;
		} else if (nextPos < prTree.getChildCount()
				&& prTree.getChild(nextPos).getText().compareTo(nowhere) == 0) {
			nextPos++;
		}

		// parameters (if present)
		if (nextPos < prTree.getChildCount() && prTree.getChildCount() == (nextPos + 1)
				&& prTree.getChild(nextPos).getText().compareTo(parameters) == 0) {
			Tree parametersTree = prTree.getChild(nextPos);
			parseParametersTree(prRule, parametersTree);
		}

		return prRule;
	}

	private void parseDependsOnTree(ProjectionRule prRule, Tree dependsOnTree, boolean isDependsOn,
			Collection<String> dynRefIdList) {

		logger.debug("dependsOnTree = " + dependsOnTree.toStringTree());
		for (int i = 0; i < dependsOnTree.getChildCount(); ++i) {
			String type = dependsOnTree.getChild(i).getText();
			String prId = dependsOnTree.getChild(i).getChild(0).getText();
			DependencyObject dependsObject = null;
			if (dependsOnTree.getChild(i).getChildCount() == 1) {
				dependsObject = new DependencyObjOneParam(prId, type, isDependsOn);
			} else if (dependsOnTree.getChild(i).getChildCount() == 2) {
				String otherValue = "";
				if (uimaType.compareTo(dependsOnTree.getChild(i).getChild(1).getText()) == 0) {
					Tree uimaTypeTree = dependsOnTree.getChild(i).getChild(1);
					for (int k = 0; k < uimaTypeTree.getChildCount(); ++k) {
						otherValue += uimaTypeTree.getChild(k).getText();
					}
				} else {
					// this depend type has two children (or at least I take only the first two child)
					otherValue = dependsOnTree.getChild(i).getChild(1).getText();
				}
				dependsObject = new DependencyObjTwoParam(prId, type, otherValue, isDependsOn);
			}/*
			 * else if (dependsOnTree.getChild(i).getChildCount() == 3) { String value2 = "", value3 = "";
			 * //value1 = dependsOnTree.getChild(i).getChild(0).getText(); value2 =
			 * dependsOnTree.getChild(i).getChild(1).getText(); value3 =
			 * dependsOnTree.getChild(i).getChild(2).getText(); dependsObject = new
			 * DependencyObjThreeParam(prId, type, value2, value3, isDependsOn); }
			 */
			else { // more than 2 child
				int numChild = dependsOnTree.getChild(i).getChildCount();
				boolean isDynamicDep = false;
				String[] childArray = new String[numChild-1];
				for (int k = 1; k < numChild; ++k) {
					if (uimaType.compareTo(dependsOnTree.getChild(i).getChild(k).getText()) == 0) {
						Tree uimaTypeTree = dependsOnTree.getChild(i).getChild(k);
						childArray[k] = "";
						for (int j = 0; j < uimaTypeTree.getChildCount(); ++k) {
							childArray[k-1] += uimaTypeTree.getChild(j).getText();
						}
					}
					else{
						childArray[k-1] = dependsOnTree.getChild(i).getChild(k).getText();
					}
				}
				if (type.compareTo(lastOneOfDep) == 0) {
					isDynamicDep = true;
					dynRefIdList.add(prId);
				}
				dependsObject = new DependencyObjVarParam(prId, type, isDependsOn, isDynamicDep, childArray);
			}
			logger.debug("\ttype = " + type + " prId = " + prId);
			prRule.addTempDependency(type, dependsObject);
		}
	}

	private void parseAliasTree(ProjectionRule prRule, Tree aliasesTree) throws PRParserException {

		logger.debug("aliasesTree = " + aliasesTree.toStringTree());
		for (int i = 0; i < aliasesTree.getChildCount(); ++i) {
			Tree aliasTree = aliasesTree.getChild(i);

			logger.debug("\taliasTree = " + aliasTree.toStringTree());
			String id = aliasTree.getChild(0).getChild(0).getText();
			Tree uimaTypeAndFeatTree = aliasTree.getChild(1);
			String uimaType = "";
			Tree uimaTypeTree = uimaTypeAndFeatTree.getChild(0);
			for (int k = 0; k < uimaTypeTree.getChildCount(); ++k) {
				uimaType += uimaTypeTree.getChild(k).getText();
			}
			String uimaFeat = "";
			boolean inBrackets = false;
			if (uimaTypeAndFeatTree.getChildCount() > 1) {
				Tree uimaFeatTree = uimaTypeAndFeatTree.getChild(1);
				for (int k = 0; k < uimaFeatTree.getChildCount(); ++k) {
					String nextValue = uimaFeatTree.getChild(k).getText();
					if (k != 0) {
						if (nextValue.compareTo("[") == 0) {
							inBrackets = true;
						} else if (nextValue.compareTo("]") == 0) {
							inBrackets = false;
						} else if (inBrackets) {
						} else
							uimaFeat += "/";
					}
					uimaFeat += nextValue;
				}
			}
			String uimaTypeAndFeat = uimaType + ":" + uimaFeat;
			PlaceholderStruct aliasStruct = new PlaceholderStruct(id, uimaTypeAndFeat, prRule);
			prRule.addPlaceholder(aliasStruct);
		}
	}

	private void parseNodesTree(ProjectionRule prRule, Tree nodesTree) throws PRParserException {

		logger.debug("nodesTree = " + nodesTree.toStringTree());
		for (int i = 0; i < nodesTree.getChildCount(); ++i) {
			Tree nodeTree = nodesTree.getChild(i);

			logger.debug("\tnodeTree = " + nodeTree.toStringTree());
			String id = nodeTree.getChild(0).getChild(0).getText();
			String type = "";
			Tree typeTree = nodeTree.getChild(1);
			for (int k = 0; k < typeTree.getChildCount(); ++k) {
				type += typeTree.getChild(k).getText();
			}
			if (type.startsWith("literal") && type.contains("(")) {
				String typeOfType = type.split("\\(")[1].split("\\)")[0];
				String typeOfTypeUri = substitutePrefix(typeOfType.split(":")[0]);
				type = type.split("\\(")[0] + "(" + typeOfTypeUri + typeOfType.split(":")[1] + ")";
			}
			// check if the next element in the nodeTree is a uimaTypeAndFeat or a if/else
			PlaceholderStruct placeholderStruct = null;
			if (nodeTree.getChild(2).getText().compareTo(UIMATYPEANDFEATS) == 0) {
				// a uima type is directly present, so there is no if/struct structure
				Tree uimaTypeAndFeatTree = nodeTree.getChild(2);
				String uimaType = "";
				Tree uimaTypeTree = uimaTypeAndFeatTree.getChild(0);
				for (int k = 0; k < uimaTypeTree.getChildCount(); ++k) {
					uimaType += uimaTypeTree.getChild(k).getText();
				}
				String uimaFeat = "";
				if (uimaTypeAndFeatTree.getChildCount() > 1) {
					Tree uimaFeatTree = uimaTypeAndFeatTree.getChild(1);
					boolean inBrackets = false;
					for (int k = 0; k < uimaFeatTree.getChildCount(); ++k) {
						String nextValue = uimaFeatTree.getChild(k).getText();
						if (k != 0) {
							if (nextValue.compareTo("[") == 0) {
								inBrackets = true;
							} else if (nextValue.compareTo("]") == 0) {
								inBrackets = false;
							} else if (inBrackets) {
							} else
								uimaFeat += "/";
						}
						uimaFeat += nextValue;
					}
				}
				String uimaTypeAndFeat = uimaType + ":" + uimaFeat;
				placeholderStruct = new PlaceholderStruct(id, type, uimaTypeAndFeat, prRule);
			} else { // a if/else structure is present
				Tree ifElseStructureTree = nodeTree.getChild(2);

				logger.debug("\tifElseStructureTree = " + ifElseStructureTree.toStringTree());
				int nextPos = 0;
				List<IfElseStruct> ifElseList = new ArrayList<IfElseStruct>();
				// first analyze the if part (which is always present)
				Tree ifTree = ifElseStructureTree.getChild(nextPos);

				logger.debug("\tifTree = " + ifTree.toStringTree());
				nextPos++;
				IfElseStruct ifStruct;
				String condIfType = "if";
				String condIfAlias = ifTree.getChild(0).getChild(0).getText();
				PlaceholderStruct condIfAliasPlaceholder = prRule.getPlaceholderMap().get(condIfAlias);
				String condIfOper = ifTree.getChild(0).getChild(1).getText();
				String condIfValue = "";
				for (int k = 2; k < ifTree.getChild(0).getChildCount(); ++k) {
					condIfValue += ifTree.getChild(0).getChild(k).getText() + " ";
				}
				// check if there is a uimaTypeAndFeat, a prefix o a URI
				String switcher = ifTree.getChild(1).getText();
				String value;
				boolean isValueAUimaTypeAndFeat;
				if (switcher.compareTo(UIMATYPEANDFEATS) == 0) {
					// the value should be taken from a uima type and feat
					isValueAUimaTypeAndFeat = true;
					value = getUIMATypeAndFeatString(ifTree.getChild(1));
				} else {
					// the value is a ontology resource (class or property), with a prefix or the
					// complete uri
					isValueAUimaTypeAndFeat = false;
					value = getOntoResURIString(ifTree.getChild(1));
				}
				ifStruct = new IfElseStruct(condIfType, value, isValueAUimaTypeAndFeat,
						condIfAliasPlaceholder, condIfOper, condIfValue.trim());
				ifElseList.add(ifStruct);
				// then analyze all the else if part (that may not exist)
				if (nextPos < ifElseStructureTree.getChildCount()) {
					while ((nextPos < ifElseStructureTree.getChildCount())
							&& ifElseStructureTree.getChild(nextPos).getText().compareTo(ELSEIF) == 0) {
						IfElseStruct elseIfStruct;
						Tree elseIfTree = ifElseStructureTree.getChild(nextPos);

						logger.debug("\telseIfTree = " + elseIfTree.toStringTree());
						nextPos++;
						String condElseIfType = "else if";
						String condElseIfAlias = elseIfTree.getChild(0).getChild(0).getText();
						PlaceholderStruct condElseIfAliasPlaceholder = prRule.getPlaceholderMap().get(
								condElseIfAlias);
						String condElseIfOper = elseIfTree.getChild(0).getChild(1).getText();
						String condElseIfValue = "";
						for (int k = 2; k < elseIfTree.getChild(0).getChildCount(); ++k) {
							condElseIfValue += elseIfTree.getChild(0).getChild(k).getText() + " ";
						}
						// check if there is a uimaTypeAndFeat, a prefix o a URI
						switcher = elseIfTree.getChild(1).getText();
						if (switcher.compareTo(UIMATYPEANDFEATS) == 0) {
							// the value should be taken from a uima type and feat
							isValueAUimaTypeAndFeat = true;
							value = getUIMATypeAndFeatString(elseIfTree.getChild(1));
						} else {
							// the value is a ontology resource (class or property), with a prefix or the
							// complete uri
							isValueAUimaTypeAndFeat = false;
							value = getOntoResURIString(elseIfTree.getChild(1));
						}
						elseIfStruct = new IfElseStruct(condElseIfType, value, isValueAUimaTypeAndFeat,
								condElseIfAliasPlaceholder, condElseIfOper, condElseIfValue.trim());
						ifElseList.add(elseIfStruct);
					}
				}
				// now analyze the else part (which may not exist)
				if (nextPos < ifElseStructureTree.getChildCount()) {
					if (ifElseStructureTree.getChild(nextPos).getText().compareTo(ELSE) == 0) {
						IfElseStruct elseStruct;
						Tree elseTree = ifElseStructureTree.getChild(nextPos);

						logger.debug("\telseTree = " + elseTree.toStringTree());
						nextPos++;
						String condElseType = "else";
						Tree uimaTypeElseTree = elseTree.getChild(0).getChild(0);
						// check if there is a uimaTypeAndFeat, a prefix o a URI
						switcher = elseTree.getChild(0).getText();
						if (switcher.compareTo(UIMATYPEANDFEATS) == 0) {
							// the value should be taken from a uima type and feat
							isValueAUimaTypeAndFeat = true;
							value = getUIMATypeAndFeatString(elseTree.getChild(0));
						} else {
							// the value is a ontology resource (class or property), with a prefix or the
							// complete uri
							isValueAUimaTypeAndFeat = false;
							value = getOntoResURIString(elseTree.getChild(0));
						}
						elseStruct = new IfElseStruct(condElseType, value, isValueAUimaTypeAndFeat, null,
								null, null);
						ifElseList.add(elseStruct);
					}
				}
				placeholderStruct = new PlaceholderStruct(id, type, ifElseList, prRule);
			}
			prRule.addPlaceholder(placeholderStruct);
		}
	}

	private String getUIMATypeAndFeatString(Tree uimaTypeAndFeatTree) {

		logger.debug("\tuimaTypeAndFeatTree = " + uimaTypeAndFeatTree.toStringTree());
		Tree uimaTypeTree = uimaTypeAndFeatTree.getChild(0);
		String uimaTypeIf = "";
		for (int k = 0; k < uimaTypeTree.getChildCount(); ++k) {
			uimaTypeIf += uimaTypeTree.getChild(k).getText();
		}
		String uimaFeatIf = "";
		if (uimaTypeAndFeatTree.getChildCount() > 1) {
			Tree uimaFeatTree = uimaTypeAndFeatTree.getChild(1);
			for (int k = 0; k < uimaFeatTree.getChildCount(); ++k) {
				if (k != 0)
					uimaFeatIf += "/";
				uimaFeatIf += uimaFeatTree.getChild(k).getText();
			}
		}
		String uimaTypeAndFeat = uimaTypeIf + ":" + uimaFeatIf;
		return uimaTypeAndFeat;
	}

	private String getOntoResURIString(Tree ontoResTree) throws PRParserException {

		logger.debug("\tontoResTree = " + ontoResTree.toStringTree());
		String uri;
		if (ontoResTree.getChild(1).getText().compareTo(":") == 0) {
			String prefix = ontoResTree.getChild(0).getText();
			String namespace = substitutePrefix(prefix);
			uri = namespace + ontoResTree.getChild(2).getText();
		} else {
			uri = "";
			for (int k = 0; k < ontoResTree.getChildCount(); ++k) {
				uri += ontoResTree.getChild(k).getText();
			}
		}
		return uri;
	}

	private void parseGraphTree(ProjectionRule projRule, Tree graphTree, Collection<String> dynRefIdList)
			throws PRParserException {

		logger.debug("graphTree = " + graphTree.toStringTree());
		for (int i = 0; i < graphTree.getChildCount(); ++i) {
			Tree tripleTree = graphTree.getChild(i);

			logger.debug("\ttripleTree = " + tripleTree.toStringTree());
			GraphSingleElement subj = parseSingleGraphTree(tripleTree.getChild(0), projRule, false,
					dynRefIdList);

			GraphSingleElement pred = parseSingleGraphTree(tripleTree.getChild(1), projRule, false,
					dynRefIdList);

			GraphSingleElement obj = parseSingleGraphTree(tripleTree.getChild(2), projRule, false,
					dynRefIdList);

			GraphStruct graphStruct;
			if (tripleTree.getText().compareToIgnoreCase(optTriple) == 0)
				graphStruct = new GraphStruct(subj, pred, obj, true);
			else
				graphStruct = new GraphStruct(subj, pred, obj);
			projRule.addTripleToGraph(graphStruct);
		}
	}

	private GraphSingleElement parseSingleGraphTree(Tree singleGraphTree, ProjectionRule prRule,
			boolean isWhere, Collection<String> dynRefIdList) throws PRParserException {

		logger.debug("\t\tsingleGraphElemTree = " + singleGraphTree.toStringTree());
		String switcher = singleGraphTree.getChild(0).getText();
		if (switcher.compareTo(placeholderSwitch) == 0) { // the element represent a placeholder
			GraphSingleElemPlaceholder graphSinglePlaceholder;
			if (singleGraphTree.getChild(0).getChildCount() == 1) {// internal reference
				String placeHolderId = singleGraphTree.getChild(0).getChild(0).getText();
				graphSinglePlaceholder = new GraphSingleElemPlaceholder(placeHolderId, prRule);
			} else {// external reference, TODO check if it is an imports or a dependsOn, and check if it is a
				// dynamic reference
				String otherPrId = singleGraphTree.getChild(0).getChild(0).getText();
				String placeHolderId = singleGraphTree.getChild(0).getChild(1).getText();
				boolean dynRef = false;
				if (dynRefIdList.contains(otherPrId)){
					dynRef = true;
				}
				graphSinglePlaceholder = new GraphSingleElemPlaceholder(placeHolderId, otherPrId, dynRef,
						prRule);
				// if (prRule.getDependsPrList().contains(otherPrId) == false)
				// graphSinglePlaceholder.setIssue(true);
			}
			return graphSinglePlaceholder;
		} else if (switcher.compareTo(varSwitch) == 0) { // the element represent a var
			GraphSingleElemVar graphSingleVar;
			String varId = singleGraphTree.getChild(0).getChild(0).getText();
			if (isWhere == true)
				prRule.addVar(varId);
			graphSingleVar = new GraphSingleElemVar(varId, prRule);
			return graphSingleVar;
		} else if (switcher.compareTo(datatypeSwitch) == 0) { // it is a simple number or string
			GraphSingleElemString graphSingleStringValue;
			String stringValue = "";
			for (int i = 0; i < singleGraphTree.getChild(0).getChildCount(); ++i) {
				stringValue += " " + singleGraphTree.getChild(0).getChild(i).getText();
			}
			graphSingleStringValue = new GraphSingleElemString(stringValue.trim(), prRule);
			return graphSingleStringValue;
		} else {// it is an ontology resource (abbreviation, class or property)
			GraphSingleElemUri graphSingleUri = null;
			if (singleGraphTree.getChildCount() == 1) { // abbreviation
				String abbr = singleGraphTree.getChild(0).getText();
				String uriFromAbbr = "";
				if (abbr.compareTo("a") == 0)
					uriFromAbbr = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type";
				graphSingleUri = new GraphSingleElemUri(uriFromAbbr, prRule);
			} else if (singleGraphTree.getChild(1).getText().compareTo(":") == 0) {// prefix
				String prefix = singleGraphTree.getChild(0).getText();
				String namespace = substitutePrefix(prefix);
				String uri = namespace + singleGraphTree.getChild(2).getText();
				graphSingleUri = new GraphSingleElemUri(uri, prRule);
			} else { // complete URI
				String uri = "";
				for (int i = 0; i < singleGraphTree.getChildCount(); ++i) {
					uri += singleGraphTree.getChild(i).getText();
				}
				graphSingleUri = new GraphSingleElemUri(uri, prRule);
			}
			return graphSingleUri;
		}
	}

	private void parseWhereTree(ProjectionRule projRule, Tree whereTree, Collection<String> dynRefIdList)
			throws PRParserException {

		logger.debug("whereTree = " + whereTree.toStringTree());
		for (int i = 0; i < whereTree.getChildCount(); ++i) {
			Tree tripleTree = whereTree.getChild(i);

			logger.debug("\ttripleTree = " + tripleTree.toStringTree());
			GraphSingleElement subj = parseSingleGraphTree(tripleTree.getChild(0), projRule, true,
					dynRefIdList);

			GraphSingleElement pred = parseSingleGraphTree(tripleTree.getChild(1), projRule, true,
					dynRefIdList);

			GraphSingleElement obj = parseSingleGraphTree(tripleTree.getChild(2), projRule, true,
					dynRefIdList);

			GraphStruct graphStruct;
			if (tripleTree.getText().compareToIgnoreCase(optTriple) == 0)
				graphStruct = new GraphStruct(subj, pred, obj, true);
			else
				graphStruct = new GraphStruct(subj, pred, obj);
			projRule.addTripleToWhere(graphStruct);
		}
	}

	private void parseParametersTree(ProjectionRule projRule, Tree parametersTree) {

		logger.debug("parametersTree = " + parametersTree.toStringTree());
		for (int i = 0; i < parametersTree.getChildCount(); ++i) {
			String attName = "";
			String attValue = "";
			Tree paramTree = parametersTree.getChild(i);

			Tree attNameTree = paramTree.getChild(0);
			for (int k = 0; k < attNameTree.getChildCount(); ++k) {
				attName += attNameTree.getChild(k);
			}
			if (paramTree.getChildCount() > 1) {
				Tree attValueTree = paramTree.getChild(1);
				for (int k = 0; k < attValueTree.getChildCount(); ++k) {
					attValue += attValueTree.getChild(k);
				}
			} else {
				attValue = "default";
			}
			projRule.addParameter(attName, attValue);
		}

	}

	private String substitutePrefix(String prefix) throws PRParserException {
		if (prefixNameSpaceMap.get(prefix) == null)
			throw new PRParserException("The prefix " + prefix + " is missing");
		String namespace = prefixNameSpaceMap.get(prefix);
		return namespace;
	}

	public boolean checkCondition(IfElseStruct ifElse,
			Map<PlaceholderStruct, String> placeholderAliasToValueMap, Annotation ann) {
		PlaceholderStruct aliasPlaceholderCond = ifElse.getCondAlias();
		String valueFromAlias = placeholderAliasToValueMap.get(aliasPlaceholderCond);
		UIMACODAUtilities uimaCodaUtilities = new UIMACODAUtilities();
		if (valueFromAlias == null) {
			valueFromAlias = uimaCodaUtilities.getValueOfFeatureFromFeatPathOneValue(ann, ifElse
					.getCondAlias());
			placeholderAliasToValueMap.put(aliasPlaceholderCond, valueFromAlias);
		}
		String condOper = ifElse.getCondOper();
		String condValue = ifElse.getCondValue();
		if (condOper.compareTo("==") == 0) {
			return (valueFromAlias.compareTo(condValue) == 0);
		} else if (condOper.compareTo("!=") == 0) {
			return (valueFromAlias.compareTo(condValue) != 0);
		}

		return false;
	}

}
